home *** CD-ROM | disk | FTP | other *** search
/ Mac Easy 2010 May / Mac Life Ubuntu.iso / casper / filesystem.squashfs / usr / share / screen-resolution-extra / screenresolution-mechanism.py < prev    next >
Encoding:
Python Source  |  2009-04-06  |  12.6 KB  |  365 lines

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright (C) 2008 Fluendo Embedded S.L. (www.fluendo.com)
  5. #
  6. # This program is free software; you can redistribute it and/or modify it under
  7. # the terms of the GNU General Public License as published by the Free Software
  8. # Foundation; either version 2 of the License, or (at your option) any later
  9. # version.
  10. #
  11. # This program is distributed in the hope that it will be useful, but WITHOUT
  12. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  13. # FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  14. # details.
  15. #
  16. # You should have received a copy of the GNU General Public License along with
  17. # this program; if not, write to the Free Software Foundation, Inc.,
  18. # 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  19. #
  20. # taken from:
  21. # https://code.fluendo.com/remotecontrol/trac/browser/trunk/
  22. #         gnome_lirc_properties/backend.py?rev=217
  23. # modified by Harald Hoyer <harald@redhat.com>
  24. #
  25. # modified by Alberto Milone (tseliot) <albertomilone@alice.it>
  26.  
  27. '''
  28. Processes, which want to access this service have to acquire first
  29. the action id "com.ubuntu.xkit.mechanism.configure" from PolicyKit
  30. '''
  31.  
  32. import dbus, dbus.service, gobject, logging
  33. import os, os.path
  34. import sys
  35. from XKit import xutils, xorgparser
  36. import time
  37. import shutil
  38. import subprocess
  39.  
  40. POLICY_KIT_ACTION     = 'com.ubuntu.screenresolution.mechanism.configure'
  41. class PolicyKitAuthentication(object):
  42.     '''
  43.     Helper class to do authentication via PolicyKit
  44.     '''
  45.     def __init__(self):
  46.         super(PolicyKitAuthentication, self).__init__()
  47.         self.__pk = None
  48.         self.__pa = None
  49.  
  50.     def is_authorized(self, action_id, pid=None):
  51.         '''
  52.         Ask PolicyKit whether we are already authorized.
  53.         '''
  54.  
  55.         # Check whether the process is authorized:
  56.         if pid == None:
  57.             pid = os.getpid()
  58.             
  59.         pid = dbus.UInt32(pid)
  60.         authorized = self.policy_kit.IsProcessAuthorized(action_id, pid, False)
  61.         logging.debug('%s: authorized=%r', action_id, authorized)
  62.  
  63.         return ('yes' == authorized)
  64.  
  65.     def obtain_authorization(self, action_id, widget=None):
  66.         '''
  67.         Try to obtain authoriztation for the specified action.
  68.         '''
  69.         if self.is_authorized(action_id):
  70.             return True
  71.  
  72.         xid = (widget and widget.get_toplevel().window.xid or 0)
  73.         xid, pid = dbus.UInt32(xid), dbus.UInt32(os.getpid())
  74.  
  75.         granted = self.auth_agent.ObtainAuthorization(action_id, xid, pid)
  76.         logging.debug('%s: granted=%r', action_id, granted)
  77.  
  78.         return bool(granted)
  79.  
  80.     def __get_policy_kit(self):
  81.         '''Retreive the D-Bus interface of PolicyKit.'''
  82.  
  83.         if self.__pk:
  84.             return self.__pk
  85.  
  86.         # retreiving the interface raises DBusException on error:
  87.         service = dbus.SystemBus().get_object('org.freedesktop.PolicyKit', '/')
  88.         self.__pk = dbus.Interface(service, 'org.freedesktop.PolicyKit')
  89.         return self.__pk        
  90.  
  91.     def __get_auth_agent(self):
  92.         "Retreive the D-Bus interface of the PolicyKit authentication agent."
  93.  
  94.         if self.__pa:
  95.             return self.__pa
  96.         # retreiving the interface raises DBusException on error:
  97.         self.__pa = dbus.SessionBus().get_object(
  98.             'org.freedesktop.PolicyKit.AuthenticationAgent', '/')
  99.         return self.__pa
  100.  
  101.     auth_agent = property(__get_auth_agent)
  102.     policy_kit = property(__get_policy_kit)
  103.  
  104.  
  105. # Modern flavors of dbus bindings have that symbol in dbus.lowlevel,
  106. # for old flavours the internal _dbus_bindings module must be used.
  107.  
  108. try:
  109.     # pylint: disable-msg=E0611
  110.     from dbus.lowlevel import HANDLER_RESULT_NOT_YET_HANDLED
  111.  
  112. except ImportError:
  113.     from _dbus_bindings import HANDLER_RESULT_NOT_YET_HANDLED
  114.  
  115. class AccessDeniedException(dbus.DBusException):
  116.     '''This exception is raised when some operation is not permitted.'''
  117.  
  118.     _dbus_error_name = 'com.ubuntu.screenresolution.Mechanism.AccessDeniedException'
  119.  
  120. class UnsupportedException(dbus.DBusException):
  121.     '''This exception is raised when some operation is not supported.'''
  122.  
  123.     _dbus_error_name = 'com.ubuntu.screenresolution.Mechanism.UnsupportedException'
  124.  
  125. class UsageError(dbus.DBusException):
  126.     '''This exception is raised when some operation was not used properly.'''
  127.  
  128.     _dbus_error_name = 'com.ubuntu.screenresolution.Mechanism.UsageError'
  129.  
  130. class PolicyKitService(dbus.service.Object):
  131.     '''A D-BUS service that uses PolicyKit for authorization.'''
  132.  
  133.     def _check_permission(self, sender, action=POLICY_KIT_ACTION):
  134.         '''
  135.         Verifies if the specified action is permitted, and raises
  136.         an AccessDeniedException if not.
  137.  
  138.         The caller should use ObtainAuthorization() to get permission.
  139.  
  140.         Needs:
  141.         /usr/bin/polkit-auth --user root --grant org.freedesktop.policykit.read
  142.  
  143.         '''
  144.         if not sender:
  145.             raise AccessDeniedException('Session not authorized by PolicyKit')
  146.  
  147.         try:
  148.             policy_auth = PolicyKitAuthentication()
  149.             bus = dbus.SystemBus()
  150.             dbus_object = bus.get_object('org.freedesktop.DBus', '/')
  151.             dbus_object = dbus.Interface(dbus_object, 'org.freedesktop.DBus')
  152.  
  153.             kit = bus.get_object('org.freedesktop.PolicyKit', '/')
  154.             kit = dbus.Interface(kit, 'org.freedesktop.PolicyKit')
  155.             pid = dbus.UInt32(dbus_object.GetConnectionUnixProcessID(sender))
  156.  
  157.             granted = policy_auth.is_authorized(action, pid)
  158.             logging.info('process authorization: %r', granted)
  159.             print >> sys.stderr,  'process authorization: %r' % granted
  160.  
  161.             if not granted:
  162.                 raise AccessDeniedException('Process not authorized'
  163.                                             ' by PolicyKit')
  164.  
  165.             granted = policy_auth.policy_kit.IsSystemBusNameAuthorized(action,
  166.                                                                        sender,
  167.                                                                        False)
  168.             logging.info('authorization of system bus name: %r', granted)
  169.  
  170.             if 'yes' != granted:
  171.                 raise AccessDeniedException('Session not '
  172.                                             'authorized by PolicyKit')
  173.  
  174.         except AccessDeniedException:
  175.             logging.info("AccessDeniedException")
  176.             raise
  177.  
  178.         except dbus.DBusException, ex:
  179.             logging.info("AccessDeniedException %r",  ex)
  180.             raise AccessDeniedException(ex.message)
  181.  
  182. class BackendService(PolicyKitService):
  183.     '''A D-Bus service that PolicyKit controls access to.'''
  184.  
  185.     # pylint: disable-msg=C0103,E0602
  186.  
  187.     INTERFACE_NAME = 'com.ubuntu.ScreenResolution.Mechanism'
  188.     SERVICE_NAME   = 'com.ubuntu.ScreenResolution.Mechanism'
  189.     IDLE_TIMEOUT   =  30
  190.  
  191.     def __init__(self, connection=None, path='/'):        
  192.         if connection is None:
  193.             connection = get_service_bus()
  194.  
  195.         super(BackendService, self).__init__(connection, path)
  196.  
  197.         self.__name = dbus.service.BusName(self.SERVICE_NAME, connection)
  198.         self.__loop = gobject.MainLoop()
  199.         self.__timeout = 0
  200.         connection.add_message_filter(self.__message_filter)
  201.  
  202.     def __message_filter(self, connection, message):
  203.         '''
  204.         D-BUS message filter that keeps the service alive,
  205.         as long as it receives message.
  206.         '''
  207.  
  208.         if self.__timeout:
  209.             self.__start_idle_timeout()
  210.  
  211.         return HANDLER_RESULT_NOT_YET_HANDLED
  212.  
  213.     def __start_idle_timeout(self):
  214.         '''Restarts the timeout for terminating the service when idle.'''
  215.  
  216.         if self.__timeout:
  217.             gobject.source_remove(self.__timeout)
  218.  
  219.         self.__timeout = gobject.timeout_add(self.IDLE_TIMEOUT * 1000,
  220.                                              self.__timeout_cb)
  221.  
  222.     def __timeout_cb(self):
  223.         '''Timeout callback that terminates the service when idle.'''
  224.  
  225.         # Keep service alive, as long as additional objects are exported:
  226.         if self.connection.list_exported_child_objects('/'):
  227.             return True
  228.  
  229.         print 'Terminating %s due to inactivity.' % self.SERVICE_NAME
  230.         self.__loop.quit()
  231.  
  232.         return False
  233.  
  234.     def run(self):
  235.         '''Creates a GLib main loop for keeping the service alive.'''
  236.  
  237.         print 'Running %s.' % self.SERVICE_NAME
  238.         print ('Terminating it after %d seconds of inactivity.' 
  239.                % self.IDLE_TIMEOUT)
  240.  
  241.         self.__start_idle_timeout()
  242.         self.__loop.run()
  243.  
  244.  
  245.     # pylint: disable-msg=R0913
  246.     @dbus.service.method(dbus_interface=INTERFACE_NAME,
  247.                          in_signature='as', out_signature='b',
  248.                          sender_keyword='sender')   
  249.     def setVirtual(self, virtres, sender=None):
  250.         '''
  251.         Replace the first line of this example with a source and a destination file
  252.         '''
  253.         virtual = ' '.join(virtres)
  254.         
  255.         source = '/etc/X11/xorg.conf'
  256.         destination = '/etc/X11/xorg.conf'
  257.         
  258.         if os.path.exists(source):
  259.             #make a backup of the xorg.conf
  260.             backup = source + "." + time.strftime("%Y%m%d%H%M%S")
  261.             shutil.copyfile(source, backup)
  262.         
  263.         try:
  264.             a = xutils.XUtils(source)
  265.         except(IOError, xorgparser.ParseException):#if xorg.conf is missing or broken
  266.             a = xutils.XUtils()#start from scratch
  267.         
  268.         empty = True
  269.         for section in a.globaldict:
  270.             if len(a.globaldict[section]) > 0:
  271.                 empty = False
  272.                 break
  273.  
  274.         if empty:
  275.             a.makeSection('Device', 'Configured Video Device')
  276.             a.makeSection('Screen', identifier='Configured Screen Device')
  277.             a.addReference('Screen', 'Device', 'Configured Video Device', position=0)
  278.             a.makeSubSection('Screen', 'Display', position=0)
  279.             a.addSubOption('Screen', 'Display', 'Virtual', value=virtual, position=0)
  280.         
  281.         else:#if xorg.conf exists and is not empty
  282.             devicelen = len(a.globaldict['Device'])
  283.             screenlen = len(a.globaldict['Screen'])
  284.             
  285.             if screenlen == 0:
  286.                 screen = a.makeSection('Screen', identifier='Configured Screen Device')
  287.                 if devicelen == 0:
  288.                     device = a.makeSection('Device', 'Configured Video Device')
  289.                 else:
  290.                     device = 0
  291.                 a.addReference('Screen', 'Device', 'Configured Video Device', position=device)
  292.                 
  293.                 a.makeSubSection('Screen', 'Display', position=0)
  294.                 a.addSubOption('Screen', 'Display', 'Virtual', value=virtual, position=0)
  295.                 
  296.             else:#if at least 1 Screen section exists
  297.                 '''
  298.                 Set the virtual section in all the Screen sections
  299.                 '''
  300.                 for screen in a.globaldict['Screen']:
  301.                     a.makeSubSection('Screen', 'Display', position=screen)
  302.                     a.addSubOption('Screen', 'Display', 'Virtual', value=virtual, position=screen)
  303.  
  304.         '''
  305.         Write the changes to the destination file
  306.         '''
  307.         a.writeFile(destination)
  308.         return True
  309.     
  310.     @dbus.service.method(dbus_interface=INTERFACE_NAME,
  311.                          in_signature='s', out_signature='i',
  312.                          sender_keyword='sender')   
  313.     def setDontZap(self, enable, sender=None):
  314.         '''Try to set the DontZap option in the xorg.conf
  315.            and return the exit code of dontzap'''
  316.         dontzap_file = '/usr/bin/dontzap'
  317.         if not os.path.isfile(dontzap_file):
  318.             logging.error('/usr/bin/dontzap does not exist')
  319.             return 1
  320.         
  321.         if enable in ['--enable', '--disable']:
  322.             logging.debug('calling dontzap with %s' % enable)
  323.             retcode = subprocess.call([dontzap_file, enable])
  324.             return retcode
  325.         else:
  326.             logging.error('called with wrong arguments = %s' % enable)
  327.             return 1
  328.     
  329.     
  330. def get_service_bus():
  331.     '''Retrieves a reference to the D-BUS system bus.'''
  332.  
  333.     return dbus.SystemBus()
  334.  
  335. def get_service(bus=None):
  336.     '''Retrieves a reference to the D-BUS driven configuration service.'''
  337.  
  338.     if not bus:
  339.         bus = get_service_bus()
  340.  
  341.     service = bus.get_object(BackendService.SERVICE_NAME, '/')
  342.     service = dbus.Interface(service, BackendService.INTERFACE_NAME)
  343.  
  344.     return service
  345.  
  346. if __name__ == '__main__':
  347.     # Support full tracing when --debug switch is passed:
  348.     import sys
  349.     from sys import argv
  350.  
  351.     # Integrate DBus with GLib main loops.
  352.  
  353.     from dbus.mainloop.glib import DBusGMainLoop
  354.     DBusGMainLoop(set_as_default=True)
  355.  
  356.     # Run the service.
  357.  
  358.     if '--debug' in argv or '-d' in argv:
  359.         logging.basicConfig(stream=sys.stderr)
  360.         logging.getLogger().setLevel(logging.NOTSET)
  361.         
  362.     BackendService().run()
  363.  
  364.